#include "ota_version.h"
#include "ota_http.h"
#include "../thirdparty/log/log.h"
#include "../thirdparty/cJSON/cJSON.h"
#include <stdlib.h>
#include <openssl/sha.h>
#include <sys/reboot.h>
#include <string.h>
#include <unistd.h>

/**
 * @brief 获取下载到本地的最新文件sha1值
 * @param file_path 文件路径
 * @return char* shal值
 */
static char *ota_version_getLocalSha1(char *file_path)
{
    FILE *file = fopen(file_path, "rb");
    if (!file)
    {
        perror("Failed to open file");
        return NULL;
    }

    unsigned char hash[SHA_DIGEST_LENGTH];
    SHA_CTX sha1;
    SHA1_Init(&sha1);

    const int bufSize = 32768;
    unsigned char *buffer = (unsigned char *)malloc(bufSize);
    if (!buffer)
    {
        perror("Failed to allocate memory");
        fclose(file);
        return NULL;
    }

    int bytesRead;
    while ((bytesRead = fread(buffer, 1, bufSize, file)) > 0)
    {
        SHA1_Update(&sha1, buffer, bytesRead);
    }

    SHA1_Final(hash, &sha1);
    fclose(file);
    free(buffer);

    char *outputBuffer = (char *)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (!outputBuffer)
    {
        perror("Failed to allocate memory");
        return NULL;
    }

    for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
    {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }

    return outputBuffer;
}

/**
 * @description: 打印远程的版本号
 */
void ota_version_getRemote(void)
{
    char *json = ota_http_getJson(OTA_URL_FILEINFO);
    cJSON *root = cJSON_Parse(json);
    int major = cJSON_GetObjectItem(root, "major")->valueint;
    int minor = cJSON_GetObjectItem(root, "minor")->valueint;
    int patch = cJSON_GetObjectItem(root, "patch")->valueint;
    log_info("major:%d, minor:%d, patch:%d", major, minor, patch);
    cJSON_Delete(root);
    free(json);
}

/**
 * @brief: 获取检查版本号并更新
 * @return: 0:成功，-1:失败
 */
int ota_version_checkUpdate(void)
{
    // 获取远程版本信息
    char *json = ota_http_getJson(OTA_URL_FILEINFO);
    cJSON *root = cJSON_Parse(json);
    int major = cJSON_GetObjectItem(root, "major")->valueint;
    int minor = cJSON_GetObjectItem(root, "minor")->valueint;
    int patch = cJSON_GetObjectItem(root, "patch")->valueint;
    // 获取远程sha1值
    char *remote_sha1 = cJSON_GetObjectItem(root, "sha1")->valuestring;
    // 打印远程版本号
    log_debug("Remote version major:%d, minor:%d, patch:%d", major, minor, patch);
    // 比较版本号，如果本地版本号小于远程版本号，则更新
    if (((major < VERSION_MAJOR) ||
         (major == VERSION_MAJOR && minor < VERSION_MINOR) ||
         (major == VERSION_MAJOR && minor == VERSION_MINOR && patch < VERSION_PATCH) ||
         (major == VERSION_MAJOR && minor == VERSION_MINOR && patch == VERSION_PATCH)))
    {
        log_debug("No need to update"); // 不需要更新
        return 0;
    }
    // 需要更新，下载远程版本
    if (ota_http_downLoadFile(OTA_URL_DOWNLOAD, OTA_LOCAL_FILE_PATH) == -1)
    {
        log_error("Download file failed");
        cJSON_Delete(root);
        free(json);
        return -1;
    }
    char *sha1 = ota_version_getLocalSha1(OTA_LOCAL_FILE_PATH);
    if (strcmp(sha1, remote_sha1) != 0)
    {
        log_error("SHA1 check failed");
        cJSON_Delete(root);
        free(json);
        free(sha1);
        // 删除本地文件
        unlink(OTA_LOCAL_FILE_PATH);
        return -1;
    }
    log_debug("Update success");
    cJSON_Delete(root);
    free(json);
    free(sha1);
    // 重启设备，运行最新版本
    reboot(RB_AUTOBOOT);
    return 0;
}

/**
 * @brief: 每日检查版本号
 */
void ota_version_checkUpdateDaily(void)
{
    while (1)
    {
        // 检查远程与本地版本号是否一致
        ota_version_checkUpdate();
        // 每日检查一次
        sleep(24 * 60 * 60);
    }
}